package Factory;

import java.net.InetAddress;

/**
 * Created by IntelliJ IDEA.
 * User: nelson
 */
public class Pacote2{


    private InetAddress ipOri;
    private InetAddress ipDes;
    private int portaOri;
    private int portaDes;
    private int numSeq;
    private int numAck;
    private int winSize;
    private int URG,ACK,PSH,RST,SYN,FIN;
    private byte[] checksum;
    private byte[] data;


    public Pacote2(InetAddress ipO, InetAddress ipD, int pO, int pD,int nSeq, int nAck, int wSize, int urg, int ack, int psh,int rst,int syn,int fin, byte[] cs, byte[] d, int tam)
    {
        this.ipOri = ipO;
        this.ipDes = ipD;
        this.portaOri = pO;
        this.portaDes = pD;
        this.numSeq = nSeq;
        this.numAck = nAck;
        this.winSize = wSize;
        this.URG = urg;
        this.ACK = ack;
        this.PSH = psh;
        this.RST = rst;
        this.SYN = syn;
        this.FIN = fin;
        //checksum = new byte[cs.length];
        checksum = cs;
        data = new byte[tam];
        for(int i=0;i<tam;i++)
            data[i] = d[i];
    }


    public Pacote2(byte[] bytes,int tam){

        byte[] buffer = new byte[4];

        int i,a,b,c,d;

        for(i =0; i<4; i++)
            buffer[i] = bytes[i];

        try{
            ipOri = InetAddress.getByAddress(buffer);
        }
        catch(Exception ex){

        }

        buffer = new byte[4];
        for(i = 4; i<8; i++)
            buffer[i-4] = bytes[i];

        try{
            ipDes = InetAddress.getByAddress(buffer);
        }
        catch(Exception ex){

        }


        buffer = new byte[4];
        for(i=8; i<12; i++){
            buffer[i-8] = bytes[i];
        }
        portaOri = bytesToInt(buffer);


        buffer = new byte[4];
        for(i=12; i<16; i++){
            buffer[i-12] = bytes[i];
        }
        portaDes = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=16; i<20; i++){
            buffer[i-16] = bytes[i];
        }
        numSeq = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=20; i<24; i++){
            buffer[i-20] = bytes[i];
        }
        numAck = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=24; i<28; i++){
            buffer[i-24] = bytes[i];
        }
        winSize = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=28; i<32; i++){
            buffer[i-28] = bytes[i];
        }
        URG = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=32; i<36; i++){
            buffer[i-32] = bytes[i];
        }
        ACK = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=36; i<40; i++){
            buffer[i-36] = bytes[i];
        }
        PSH = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=40; i<44; i++){
            buffer[i-40] = bytes[i];
        }
        RST = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=44; i<48; i++){
            buffer[i-44] = bytes[i];
        }
        SYN = bytesToInt(buffer);

        buffer = new byte[4];
        for(i=48; i<52; i++){
            buffer[i-48] = bytes[i];
        }
        FIN = bytesToInt(buffer);

        checksum = new byte[2];
        for(i = 52; i<54; i++)
            checksum[i-52] = bytes[i];

        data = new byte[tam-54];
        for(i=54; i<tam; i++)
            data[i-54] = bytes[i];

    }

	public boolean isAck()
	{
		if( this.URG == 0 &&  this.ACK == 1 && this.PSH == 0 && this.RST == 0 && this.SYN == 0 && this.FIN ==0)
			return true;
		return false;
	}

	public boolean isSyn()
	{
		if( this.URG == 0 &&  this.ACK == 0 && this.PSH == 0 && this.RST == 0 && this.SYN == 1 && this.FIN ==0)
			return true;
		return false;
	}

	public boolean isSynAck()
	{
		if( this.URG == 0 &&  this.ACK == 1 && this.PSH == 0 && this.RST == 0 && this.SYN == 1 && this.FIN ==0)
			return true;
		return false;
	}

	public boolean isFin()
	{
		if( this.URG == 0 &&  this.ACK == 0 && this.PSH == 0 && this.RST == 0 && this.SYN == 0 && this.FIN ==1)
			return true;
		return false;
	}

	public void printFlags()
	{
		System.out.print(" --> ACK:"+ACK+" SYN:"+SYN+" FIN:"+FIN+" PSH:"+PSH+" RST:"+RST+" URG:"+URG+"!\n");
	}


    public byte[] checksum16(byte data[], int offset, int length){
        int value = 0;
        byte checksum[] = new byte[2];

        for(int i = offset; i < length + offset; i += 2){
        value += data[i] << 8;
        if(i + 1 < length + offset) value += data[i+1];
        }

        value = ((value & 0xFFFF0000) >> 16) + (value & 0x0000FFFF);

        checksum[0] = (byte) ((value & 0xFF00) >> 8);
        checksum[1] = (byte) (value & 0xFF);
        return checksum;
    }

   /*//metodo que calcula o checksum do campo data que vai no pacote
    public byte[] createCheckSum(byte[] pck,boolean test) {

           byte[] checksum2 = new byte[2];

           int i;
           int acT=0,a=0,b=0;
           Integer a1,b1;


           for(i=0; i<pck.length; i= i+2){
               a = new Integer(pck[i]);
               a = ((a & 0x00FF) << 8);
               if(i+1 < pck.length){
                   b = new Integer(pck[i+1]);
                   //b = pck[i+1].intValue();
                   acT = acT + (a + b);
               }
               else
                acT = acT + a;
           }
           //System.out.println("\nA: "+a+"\n");
           //System.out.println("\nB: "+b+"\n");
           //System.out.println("\nAct: "+acT+"\n");

           if(test){
             a1 = acT & 0xFF00;
             //System.out.println("\nA1: "+a1+"\n");
             b1 = acT & 0x00FF;
             //System.out.println("\nB1: "+b1+"\n");
             checksum2[0] = a1.byteValue();//new Byte(a1.byteValue());
             checksum2[1] = b1.byteValue();//new Byte(b1.byteValue());
           }

           else{
             a1 = (~ acT) & 0xFF00;
             //System.out.println("\nA1: "+a1+"\n");
             b1 = (~ acT) & 0x00FF;
             //System.out.println("\nB1: "+b1+"\n");
             checksum2[0] = new Byte(a1.byteValue());
             checksum2[1] = new Byte(b1.byteValue());
           }
            return checksum2;
       }


       //metodo que teste se o check sum esta correcto quando o pacote chega ao destino
       public boolean testeCheckSum(){

           byte[] aux = new byte[2];
           int a,b,result,result2;

           aux = createCheckSum(data,true);

           a = new Integer(aux[0]);
           a = ((a & 0x00FF) << 8);
           b = new Integer(aux[1]);//aux[1].intValue();
           result = a + b;

           a = new Integer(checksum[0]);
           a = ((a & 0x00FF) << 8);
           b = new Integer(checksum[1]);//checksum[1].intValue();
           result2 = a + b;

           return ((result+result2+1)==0);

       }

*/

		public byte[] intToByteArray (int i)
		{
			byte[] byteArray = new byte[4];

			byteArray[0] = (byte)((i & 0xFF000000) >> 24);
			byteArray[1] = (byte)((i & 0x00FF0000) >> 16);
			byteArray[2] = (byte)((i & 0x0000FF00) >> 8);
			byteArray[3] = (byte)((i & 0x000000FF));

			return (byteArray);
		}



		public int bytesToInt(byte[] bytes)
		{
			int a,b,c,d;
			a = (bytes[0] & 0x000000FF) << 24;
			b = (bytes[1] & 0x000000FF) << 16;
			c = (bytes[2] & 0x000000FF) << 8;
			d = (bytes[3] & 0x000000FF);

			return a+b+c+d;
		}



       public byte[] toByteArray(){

           byte[] result = new byte[54+data.length];
           byte[] aux = new byte[4];

           int i;

		   if(ipOri!=null)
		   {
			   aux = ipOri.getAddress();
		       for(i = 0; i<4; i++)
				   result[i] = aux[i];
		   }
		   else
		   {
			   InetAddress ipaux = null;
			   byte aux2 [] = new byte[4];
			   try{
					ipaux = InetAddress.getByName("localhost");
			   }
			   catch(Exception ex){
				   ex.printStackTrace();
			   }

			   aux2 = ipaux.getAddress();
		       for(i = 0; i<4; i++)
				   result[i] = aux2[i];
		   }

           aux = new byte[4];
           aux = ipDes.getAddress();
           for(i = 4; i<8; i++)
               result[i] = aux[i-4];

           aux = new byte[4];
           aux = intToByteArray(portaOri);
           for(i = 8; i<12; i++)
               result[i] = aux[i-8];

           aux = new byte[4];
           aux = intToByteArray(portaDes);
           for(i = 12; i<16; i++)
               result[i] = aux[i-12];

           aux = new byte[4];
           aux = intToByteArray(numSeq);
           for(i = 16; i<20; i++)
               result[i] = aux[i-16];

           aux = new byte[4];
           aux = intToByteArray(numAck);
           for(i = 20; i<24; i++)
               result[i] = aux[i-20];

           aux = new byte[4];
           aux = intToByteArray(winSize);
           for(i = 24; i<28; i++)
               result[i] = aux[i-24];

           aux = new byte[4];
           aux = intToByteArray(URG);
           for(i = 28; i<32; i++)
               result[i] = aux[i-28];

           aux = new byte[4];
           aux = intToByteArray(ACK);
           for(i = 32; i<36; i++)
               result[i] = aux[i-32];

           aux = new byte[4];
           aux = intToByteArray(PSH);
           for(i = 36; i<40; i++)
               result[i] = aux[i-36];

           aux = new byte[4];
           aux = intToByteArray(RST);
           for(i = 40; i<44; i++)
               result[i] = aux[i-40];

           aux = new byte[4];
           aux = intToByteArray(SYN);
           for(i = 44; i<48; i++)
               result[i] = aux[i-44];

           aux = new byte[4];
           aux = intToByteArray(FIN);
           for(i = 48; i<52; i++)
               result[i] = aux[i-48];

           if(checksum != null){
            result[52] = checksum[0];
            result[53] = checksum[1];
           }

           if(data!=null){
            for(i = 54; i<data.length+54; i++)
                result[i] = data[i-54];
           }

           return result;
       }



       public byte[] intIn2bytes(int num)
	   {

			byte[] byteArray = new byte[2];

			byteArray[0] = (byte)((num & 0xFF00) >> 8);
			byteArray[1] = (byte)((num & 0x00FF));


			return (byteArray);
       }



    public InetAddress getIpOri(){
        return ipOri;
    }

    public InetAddress getIpDes(){
        return ipDes;
    }

    public int getPortOri(){
        return portaOri;
    }

    public int getPortDes(){
        return portaDes;
    }

    public int getnumSeq(){
        return numSeq;
    }

    public int getNumAck(){
        return numAck;
    }

    public int getWinSize(){
        return winSize;
    }

    public int getACK() {
        return ACK;
    }

    public int getFIN() {
        return FIN;
    }


    public int getPSH() {
        return PSH;
    }

    public int getRST() {
        return RST;
    }

    public int getSYN() {
        return SYN;
    }

    public int getURG() {
        return URG;
    }


    public byte[] getData(){
        return data;
    }


    //metodos Set
    public void setIpOri(InetAddress ip){
           this.ipOri = ip;
    }

    public void setIpDes(InetAddress ip){
           this.ipDes = ip;
    }

    public void setPortOri(int port){
           this.portaOri = port;
    }

    public void setPortDes(int port){
           this.portaDes = port;
    }


    public void setACK(int ACK) {
        this.ACK = ACK;
    }

    public void setFIN(int FIN) {
        this.FIN = FIN;
    }

    public void setPSH(int PSH) {
        this.PSH = PSH;
    }

    public void setRST(int RST) {
        this.RST = RST;
    }

    public void setSYN(int SYN) {
        this.SYN = SYN;
    }

    public void setURG(int URG) {
        this.URG = URG;
    }

    public void setNumAck(int numAck) {
        this.numAck = numAck;
    }

    public void setNumSeq(int numSeq) {
        this.numSeq = numSeq;
    }

    public void setWinSize(int winSize) {
        this.winSize = winSize;
    }

    public void setData(byte[] data){
           this.data = data;
    }

     public void setChecksum(byte[] checksum) {
        this.checksum = checksum;
    }

    public void setPortaDes(int portaDes) {
        this.portaDes = portaDes;
    }

    public void setPortaOri(int portaOri) {
        this.portaOri = portaOri;
    }
}

